package com.framework.service.config.initSecurityConfig;

import com.framework.common.model.properties.IgnoredUrlsProperties;
import com.framework.common.util.filter.FilterStringUtil;
import com.framework.common.util.other.NumeralUtil;
import com.framework.service.config.initSecurityConfig.initLogin.MyAuthenticationFailureHandler;
import com.framework.service.config.initSecurityConfig.initLogin.MyAuthenticationLogoutHandler;
import com.framework.service.config.initSecurityConfig.initLogin.MyAuthenticationProvider;
import com.framework.service.config.initSecurityConfig.initLogin.MyAuthenticationSuccessHandler;
import com.framework.service.config.initSecurityConfig.initLogin.MyPersistentTokenRepository;
import com.framework.service.config.initSecurityConfig.initLogin.RememberMeConfig;
import com.framework.service.other.filter.ParameterValueFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.util.PathMatcher;

/**
 * @author 龘鵺
 * @version 1.0
 * @className com.framework.service.config.initSecurityConfig
 * @description web请求安全拦截配置
 * @datetime 2019-01-09 11:11:11
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    //    @Autowired
//    private InterceptorConfig interceptorConfig;
    /**
     * 登录记住我选择，(单位：秒)
     */
    @Value("${spring.security.remember-me-time}")
    private Integer rememberMeTime;
    /**
     * 自定义身份验证实现类
     */
    @Autowired
    private MyAuthenticationProvider myAuthenticationProvider;
    /**
     * 登录成功处理
     */
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    /**
     * 登录失败处理
     */
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    /**
     * 退出处理
     */
    @Autowired
    private MyAuthenticationLogoutHandler myAuthenticationLogoutHandler;
    /**
     * 自定义用户登录信息业务实现类
     */
    //    @Autowired
//    private MyUserDetailsService myUserDetailsService;
    /**
     * 自定义redis
     */
    @Autowired
    private MyPersistentTokenRepository myPersistentTokenRepository;
    /**
     * 持久令牌存储库-处理
     */
    //    @Autowired
//    private PersistentTokenRepository persistentTokenRepository;
    /**
     * 记住我业务初始化设置
     */
    @Autowired
    private RememberMeServices rememberMeService;
//    @Autowired
//    private ParameterValueFilter parameterValueFilter;
    /**
     * url权限验证处理
     */
//    @Autowired
//    private AccessDecisionManager myAccessDecisionManager;
//    @Autowired
//    private FilterInvocationSecurityMetadataSource mySecurityMetadataSource;
    @Autowired
    private IgnoredUrlsProperties ignoredUrlsProperties;
    @Autowired
    private PathMatcher pathMatcher;

    /**
     * @return org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
     * @title 配置请求过滤
     * @description 配置请求过滤
     * @author 龘鵺
     * @datetime 2025-01-09 11:11:11
     */
    @Bean
    protected WebSecurityCustomizer webSecurityCustomizer() {
        //Web层面的拦截，用来跳过的资源
        return (web) -> {
            ignoredUrlsProperties.getInitViewIgnoreUrl().forEach(item -> {
                web.ignoring()
                        .antMatchers(item);
            });
        };
    }

    /**
     * @param http 1 安全初始化
     * @return org.springframework.security.web.SecurityFilterChain
     * @title 配置 Security 初始化设置
     * @description 配置 Security 初始化设置
     * @author 龘鵺
     * @datetime 2025-01-09 11:11:11
     */
    @Bean
    protected SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
//        , AuthenticationConfiguration authenticationConfiguration
//        ProviderManager providerManager = (ProviderManager) authenticationConfiguration.getAuthenticationManager();
//        System.out.println(providerManager.getProviders().size());
        //以下的请求都不需要认证
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
                .authorizeRequests();
        for (String url : ignoredUrlsProperties.getInitIgnoreUrl()) {
            registry.antMatchers(url).permitAll();
        }
        registry
                .antMatchers(FilterStringUtil.FILTER_STRING_LOGIN_PAGE).permitAll()
//                .antMatchers("/myws").permitAll()
                .antMatchers(FilterStringUtil.FILTER_STRING_DEFAULT_CAPTCHA)
                .permitAll().anyRequest()
                .authenticated();

        //前后端分离放开此处
        //使用这个是不会走多次拦截器。
//        registry.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
//            @Override
//            public <O extends FilterSecurityInterceptor> O postProcess(O object) {
//                object.setAccessDecisionManager(myAccessDecisionManager);//决策管理器
//                object.setSecurityMetadataSource(mySecurityMetadataSource);//安全元数据源
//                return object;
//            }
//        });
        //请求之前拦截处理器
//        http.addFilterBefore(testFilter, UsernamePasswordAuthenticationFilter.class);
        //请求之后拦截处理器
//        http.addFilter()
        http.addFilterAfter(new ParameterValueFilter(ignoredUrlsProperties, pathMatcher), LogoutFilter.class);
        //登录处理
        http.formLogin()
                .loginPage(FilterStringUtil.FILTER_STRING_LOGIN)
                .usernameParameter(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY)
                .passwordParameter(UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY)
                //成功跳转
                .successForwardUrl(FilterStringUtil.FILTER_STRING_INDEX)
                //成功处理
                .successHandler(myAuthenticationSuccessHandler)
                //失败处理
                .failureHandler(myAuthenticationFailureHandler)
                .permitAll();
        //退出处理
        http.logout()
                .logoutSuccessHandler(myAuthenticationLogoutHandler)
//                .deleteCookies(RememberMeConfig.REMEMBER_ME)
                .invalidateHttpSession(true);
        //记住账号处理
        //记住我相关配置-数据库四线
//        http.rememberMe()
////                .rememberMeCookieName(RememberMeConfig.REMEMBER_ME)
//                .rememberMeServices(rememberMeService)
//                .key(RememberMeConfig.INTERNAL_SECRET_KEY)
//                //设置TokenRepository
//                .tokenRepository(persistentTokenRepository)//设置操作表的Repository，数据库格式存储
//                // 配置UserDetailsService
////                .userDetailsService(myUserDetailsService)
//                // 配置Cookie过期时间
//                .tokenValiditySeconds(rememberMeTime);

        //记住我相关配置-redis实现
        //RememberMeAuthenticationFilter=AbstractRememberMeServices.autoLogin=UserDetailsChecker.check
        http.rememberMe()
//                .rememberMeCookieName(RememberMeConfig.REMEMBER_ME)
                .rememberMeServices(rememberMeService)
                .key(RememberMeConfig.INTERNAL_SECRET_KEY)
                //设置TokenRepository
                .tokenRepository(myPersistentTokenRepository)//redis格式存储
                // 配置UserDetailsService
//                .userDetailsService(myUserDetailsService)
                // 配置Cookie过期时间,(单位：秒)
                .tokenValiditySeconds(rememberMeTime);

        //关闭csrf保护，
        http.csrf().disable();
        //关闭安全注入的头headers，解决同域名下iframe请求处理
        http.headers().frameOptions().sameOrigin();
        // session管理

//        http.sessionManagement().invalidSessionUrl("/loginPage?invalid");
//        http.sessionManagement().maximumSessions(NumeralUtil.POSITIVE_ONE).maxSessionsPreventsLogin(true).expiredUrl("/loginPage");
        http.sessionManagement()
                .sessionFixation().changeSessionId()
                // session失效后跳转
                .invalidSessionUrl(FilterStringUtil.FILTER_STRING_LOGIN_PAGE_INVALID)
                // 只允许一个用户登录,如果同一个帐号两次登录,那么第一个帐号将被踢下线,跳转到登录页面
                .maximumSessions(NumeralUtil.POSITIVE_ONE).expiredUrl(FilterStringUtil.FILTER_STRING_LOGIN_PAGE);

        //以下代码屏蔽security安全拦截，跨域，header头部一些处理
//        http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll()
//                .and().headers().frameOptions().disable().and().csrf().disable();

        //关闭匿名身份验证器
//        http.anonymous().disable();

        //重实现身份验证管理器生成器
        http.authenticationProvider(myAuthenticationProvider);

        return http.build();
    }

    /**
     * ExpressionInterceptUrlRegistry 和 FilterSecurityInterceptor好像二选一。 等实际需要使用的时候测试一下。
     */
//    //URL权限验证处理
//    @Bean
//    public FilterSecurityInterceptor filterSecurityInterceptor() {
//        FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
//        filterSecurityInterceptor.setAccessDecisionManager(myAccessDecisionManager);
//        // 不配置动态权限
//        // filterSecurityInterceptor.setSecurityMetadataSource(filterInvocationSecurityMetadataSource());
//        // 第一种设置动态权限
//        filterSecurityInterceptor.setSecurityMetadataSource(mySecurityMetadataSource);
//        filterSecurityInterceptor.setObserveOncePerRequest(false);
//        return filterSecurityInterceptor;
//    }
}
